﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Forms;

using HBFFirmwareGetter.Code;
using HBFFirmwareGetter.Helpers;
using HBFFirmwareGetter.Properties;

namespace HBFFirmwareGetter
{
	/// <summary>
	/// Represents application main form class.
	/// </summary>
	public partial class HBFForm : Form
	{
		#region Constructor

		/// <summary>
		/// Initializes a new instance of the <see cref="HBFForm"/> class.
		/// </summary>
		public HBFForm()
		{
			InitializeComponent();
			InitializeBackgroundWorker();

			PreloadSettings();

			Core.OnFirmwareFound += new Core.FirmwareFoundEventHandler(Core_OnFirmwareFound);
			Core.OnFileProcessed += new Core.FileProcessedEventHandler(Core_OnFileProcessed);
		}

		#endregion Constructor

		#region Private Fields

		private List<string> resultCollection = new List<string>();

		private int foundCounter = 0;

		#endregion Private Fields

		#region Handlers

		#region Form Handlers

		/// <summary>
		/// Handles the FormClosing event of the HBFForm control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> instance containing the event data.</param>
		private void HBFForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			SaveSettings();
		}

		#endregion Form Handlers

		#region CheckBox Handlers

		/// <summary>
		/// Handles the CheckedChanged event of the cbUseProxy control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void cbUseProxy_CheckedChanged(object sender, EventArgs e)
		{
			SetProxyGroupEnabled(cbUseProxy.Checked);
		}

		/// <summary>
		/// Handles the CheckedChanged event of the cbNeedAuthorization control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void cbNeedAuthorization_CheckedChanged(object sender, EventArgs e)
		{
			SetProxyAuthorizationEnabled(cbNeedAuthorization.Checked);
		}

		/// <summary>
		/// Handles the CheckedChanged event of the cbFullMatch control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void cbFullMatch_CheckedChanged(object sender, EventArgs e)
		{
			SetFullMatch(cbFullMatch.Checked);
		}

		#endregion CheckBox Handlers

		#region Button Handlers

		/// <summary>
		/// Handles the Click event of the btnScan control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void btnScan_Click(object sender, EventArgs e)
		{
			this.foundCounter = 0;

			Core.InitializeCore(
				cbUseProxy.Checked,
				nudPort.Value,
				mtxtAddress.Text,
				txtLogin.Text,
				txtPassword.Text,
				cbNeedAuthorization.Checked,
				nudTimeout.Value,
				nudFilesPerThread.Value
				);

			LockForm(true);
			bwScanner.RunWorkerAsync();
		}

		#endregion Button Handlers

		#region Core Event Handlers

		/// <summary>
		/// Handles the OnFirmwareFound event of the Core control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="HBFFirmwareGetter.Code.FirmwareFoundEventArgs"/> instance containing the event data.</param>
		private void Core_OnFirmwareFound(object sender, FirmwareFoundEventArgs e)
		{
			if (!String.IsNullOrEmpty(e.FirmwareName))
			{
				resultCollection.Add(String.Format("{0} - {1}", e.FirmwareName, e.URL.URL));

				this.foundCounter++;
			}
		}

		/// <summary>
		/// Core_s the on file processed.
		/// </summary>
		/// <param name="sender">The sender.</param>
		private void Core_OnFileProcessed(object sender)
		{
			if (sender is double)
			{
				lblStatus.Text = String.Format(Constant.PROCESSING_STATUS_MESSAGE_FORMAT_STRING, sender, this.foundCounter);
			}
		}

		#endregion Core Event Handlers

		#region Numeric UpDown Handlers

		/// <summary>
		/// Handles the ValueChanged event of the NumericUpDown control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void NumericUpDown_ValueChanged(object sender, EventArgs e)
		{
			SaveSettings();
		}

		#endregion Numeric UpDown Handlers

		#endregion Handlers

		#region Interna Implementation

		/// <summary>
		/// Sets the proxy group enabled.
		/// </summary>
		/// <param name="enabled">If set to <c>true</c> [enabled], otherwise false.</param>
		private void SetProxyGroupEnabled(bool enabled)
		{
			gbProxySettings.Enabled = enabled;
		}

		/// <summary>
		/// Sets the proxy authorization enabled.
		/// </summary>
		/// <param name="enabled">If set to <c>true</c> [enabled], otherwise false.</param>
		private void SetProxyAuthorizationEnabled(bool enabled)
		{
			lblLogin.Enabled = enabled;
			lblPassword.Enabled = enabled;

			txtLogin.Enabled = enabled;
			txtPassword.Enabled = enabled;
		}

		/// <summary>
		/// Sets the full match.
		/// </summary>
		/// <param name="useFullMatch">If set to <c>true</c> [use full match], otherwise false.</param>
		private void SetFullMatch(bool useFullMatch)
		{
			lblPattern.Enabled = useFullMatch;
			txtFullMatchString.Enabled = useFullMatch;
		}

		/// <summary>
		/// Preloads the settings.
		/// </summary>
		private void PreloadSettings()
		{
			nudPort.Value = Settings.Default.ProxyPort;
			nudThreads.Value = Settings.Default.Threads;
			nudTimeout.Value = Settings.Default.TimeOut;
			nudStartIndex.Value = Settings.Default.StartIndex;
			nudFilesPerThread.Value = Settings.Default.FilesPerThread;

			cbUseProxy.Checked = Settings.Default.UseProxy;
			cbNeedAuthorization.Checked = Settings.Default.NeedAuthorization;
			cbFullMatch.Checked = Settings.Default.UseFullMatch;

			mtxtAddress.Text = Settings.Default.ProxyAddress;

			txtLogin.Text = Settings.Default.Login;
			txtPassword.Text = Settings.Default.Password;
			txtFullMatchString.Text = Settings.Default.FullMatchString;
		}

		/// <summary>
		/// Saves the settings.
		/// </summary>
		private void SaveSettings()
		{
			Settings.Default.ProxyPort = nudPort.Value;
			Settings.Default.Threads = nudThreads.Value;
			Settings.Default.TimeOut = nudTimeout.Value;
			Settings.Default.StartIndex = nudStartIndex.Value;
			Settings.Default.FilesPerThread = nudFilesPerThread.Value;

			Settings.Default.UseProxy = cbUseProxy.Checked;
			Settings.Default.NeedAuthorization = cbNeedAuthorization.Checked;

			Settings.Default.ProxyAddress = mtxtAddress.Text;

			Settings.Default.Login = txtLogin.Text;
			Settings.Default.Password = txtPassword.Text;

			Settings.Default.Save();
		}

		/// <summary>
		/// Locks the form.
		/// </summary>
		/// <param name="locked">If set to <c>true</c> [locked], otherwise false.</param>
		private void LockForm(bool locked)
		{
			this.Enabled = !locked;
		}

		/// <summary>
		/// Starts the scanner.
		/// </summary>
		/// <returns></returns>
		private bool StartScanner()
		{
			int count = 0;
			double counter = (double)nudStartIndex.Value;

			List<Task> taskList = new List<Task>();
			List<Action<int>> actionList = new List<Action<int>>();

			#region Create Actions

			for (int i = 0; i < nudThreads.Value; i++)
			{
				Core.FillCounterCollection(counter);

				Action<int> action = new Action<int>((x) =>
				{
					int files = 0;
					Core.DoWork(x, ref files);
				});

				actionList.Add(action);

				counter += (double)nudFilesPerThread.Value;
			}

			#endregion

			#region Fill Task list

			foreach (var item in actionList)
			{
				Task task = new Task((obk) => item((int)obk), count);

				taskList.Add(task);

				count++;
			}

			#endregion

			#region Start Tasks

			foreach (var item in taskList)
			{
				item.Start();
			}

			#endregion

			Task.WaitAll(taskList.ToArray());

			return true;
		}

		/// <summary>
		/// Initializes the background worker.
		/// </summary>
		private void InitializeBackgroundWorker()
		{
			bwScanner.DoWork += new DoWorkEventHandler(bwScanner_DoWork);
			bwScanner.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwScanner_RunWorkerCompleted);
		}

		/// <summary>
		/// Handles the RunWorkerCompleted event of the bwScanner control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
		void bwScanner_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			LockForm(false);
			CreateResultForm();
		}

		/// <summary>
		/// Handles the DoWork event of the bwScanner control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
		void bwScanner_DoWork(object sender, DoWorkEventArgs e)
		{
			BackgroundWorker worker = sender as BackgroundWorker;

			e.Result = StartScanner();
		}

		/// <summary>
		/// Creates the result form.
		/// </summary>
		private void CreateResultForm()
		{
			Results refultForm = new Results(resultCollection);

			refultForm.Show();
		}

		#endregion Interna Implementation
	}
}
